package l1j.opqlo.Timer.血量魔量恢復;

import static l1j.server.server.model.Instance.L1PcInstance.REGENSTATE_NONE;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.Config;
import l1j.server.server.model.L1HouseLocation;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.Instance.L1EffectInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_bonusstats;
import l1j.server.server.types.Point;
import l1j.server.server.utils.Random;
import static l1j.server.server.model.skill.L1SkillId.*;

/**
 * PC HP回復執行
 *
 * @author dexc
 *
 */
public class 血量恢復控制 {

	private static Logger _log = Logger.getLogger(血量恢復控制.class.getName());

	// 技能 回復HP增加/減少 <技能編號, 影響質>
	private static final HashMap<Integer, Integer> _skill = new HashMap<Integer, Integer>();

	// 地圖 回復HP增加 <地圖編號, 影響質>
	private static final HashMap<Integer, Integer> _mapIdU = new HashMap<Integer, Integer>();

	// 地圖 回復HP減少 <地圖編號, 影響質>
	private static final HashMap<Integer, Integer> _mapIdD = new HashMap<Integer, Integer>();

	private static 血量恢復控制 _instance;

	protected static 血量恢復控制 get() {
		if (_instance == null) {
			_instance = new 血量恢復控制();
		}
		return _instance;
	}

	private static boolean isLv50Quest(final L1PcInstance pc) {
		final int mapId = pc.getMapId();
		return mapId == 2000 || mapId == 2001 ? true : false;
	}

	/**
	 * HP減少的MAP
	 *
	 * @param pc
	 * @return
	 */
	/*
	 * private static boolean isLv50Quest(final L1PcInstance pc) { final int
	 * mapId = pc.getMapId(); // 2000/2001:古代人空間1F2F 410:魔族神殿 306:黑暗妖精試煉地監
	 * return ((mapId == 2000) || (mapId == 2001) || (mapId == 410) || (mapId ==
	 * 306)) ? true : false; }
	 */

	private static boolean isOverWeight(final L1PcInstance pc) {
		// エキゾチックバイタライズ状態、アディショナルファイアー状態か
		// ゴールデンウィング装備時であれば、重量オーバーでは無いとみなす。
		if (pc.hasSkillEffect(EXOTIC_VITALIZE)
				|| pc.hasSkillEffect(ADDITIONAL_FIRE)) {
			return false;
		}
		if (pc.getInventory().checkEquipped(20049)) {
			return false;
		}

		return 120 <= pc.getInventory().getWeight240() ? true : false;
	}

	/**
	 * 法師技能(治癒能量風暴)
	 *
	 * @param pc
	 *            PC
	 * @return true PC在4格範圍內
	 */
	private static boolean isPlayerInLifeStream(final L1PcInstance pc) {
		for (final L1Object object : pc.getKnownObjects()) {
			if (object instanceof L1EffectInstance == false) {
				continue;
			}
			final L1EffectInstance effect = (L1EffectInstance) object;
			// 法師技能(治癒能量風暴)
			if (effect.getNpcId() == 81169) {
				if (effect.getLocation().getTileLineDistance(pc.getLocation()) < 4) {
					return true;
				}
			}
		}
		return false;
	}

	private static boolean isUnderwater(final L1PcInstance pc) {
		if (pc.getInventory().checkEquipped(20207)) {// 深水長靴
			return false;
		}
		if (pc.hasSkillEffect(STATUS_UNDERWATER_BREATH)) {// 伊娃的祝福藥水效果
			return false;
		}
		if (pc.getInventory().checkEquipped(21048)// 修好的戒指
				&& pc.getInventory().checkEquipped(21049)// 修好的耳環
				&& pc.getInventory().checkEquipped(21050)// 修好的項鏈
		) {
			return false;
		}

		return pc.getMap().isUnderwater();
	}

	private static void regenHp(final L1PcInstance tgpc) {
		tgpc.set_hpRegenType(0);
		int maxBonus = 1;

		// CONボーナス
		if (11 < tgpc.getLevel() && 14 <= tgpc.getCon()) {
			maxBonus = tgpc.getCon() - 12;
			if (25 < tgpc.getCon()) {
				maxBonus = 14;
			}
		}

		int equipHpr = tgpc.getInventory().hpRegenPerTick();
		equipHpr += tgpc.getHpr();
		int bonus = Random.nextInt(maxBonus) + 1;

		if (tgpc.hasSkillEffect(NATURES_TOUCH)) {
			bonus += 15;
		}
		if (L1HouseLocation
				.isInHouse(tgpc.getX(), tgpc.getY(), tgpc.getMapId())) {
			// bonus += 5;
			bonus += Config.Hp_Reg_of_INHOUSE;// TODO 可設定盟屋、旅館回血回魔量
		}
		/*
		 * if(L1CastleLocation.確認是否在主城(tgpc.getX(),
		 * tgpc.getY(),tgpc.getMapId())){//opqlo 賭肥區判斷) bonus +=
		 * Config.Hp_Reg_of_INHOUSE; }
		 */
		final Integer rhp = _mapIdU.get(new Integer(tgpc.getMapId()));
		if (rhp != null) {
			// 地圖影響
			bonus += rhp.intValue();
		}
		// 世界樹
		if (tgpc.isElf()) {
			if (tgpc.getMapId() == 4) {
				if (tgpc.getLocation().isInScreen(new Point(33055, 32336))) {
					bonus += 5;
				}
			}
		}

		// 技能補正
		if (!tgpc.getSkillisEmpty() && tgpc.getSkillEffect().size() > 0) {
			try {
				for (final Object key : tgpc.getSkillEffect().toArray()) {
					final Integer integer = _skill.get(key);
					if (integer != null) {
						bonus += integer;
					}
				}

			} catch (final ConcurrentModificationException e) {
				// 技能取回發生其他線程進行修改
			} catch (final Exception e) {
				_log.log(Level.WARNING, e.getLocalizedMessage(), e);
			}
		}
		if (tgpc.getOriginalHpr() > 0) { // オリジナルCON HPR補正
			bonus += tgpc.getOriginalHpr();
		}

		boolean inLifeStream = false;
		if (isPlayerInLifeStream(tgpc)) {
			inLifeStream = true;
			// 古代の空間、魔族の神殿ではHPR+3はなくなる？
			bonus += 3;
		}

		// 空腹と重量のチェック
		if (tgpc.get_food() < 3 || isOverWeight(tgpc)
				|| tgpc.hasSkillEffect(BERSERKERS)) {
			bonus = 0;
			// 装備によるＨＰＲ増加は満腹度、重量によってなくなるが、 減少である場合は満腹度、重量に関係なく効果が残る
			if (equipHpr > 0) {
				equipHpr = 0;
			}
		}
		// TODO 免登出可以把能力值點完by opqlo
		if (tgpc.getLevel() - 50 > tgpc.getBonusStats()) {
			if (tgpc.全屬性總和 < Config.BONUS_STATS1 * 6) {
				tgpc.sendPackets(new S_bonusstats(tgpc.getId(), 1));
			}
		}
		/*
		 * if (tgpc.getLevel() >= 51 && tgpc.getLevel() - 50 >
		 * tgpc.getBonusStats()) { if ((tgpc.getBaseStr() + tgpc.getBaseDex() +
		 * tgpc.getBaseCon() + tgpc.getBaseInt() + tgpc.getBaseWis() +
		 * tgpc.getBaseCha()) < 150) { tgpc.sendPackets(new
		 * S_bonusstats(tgpc.getId(), 1)); } }
		 */
		int newHp = tgpc.getCurrentHp();
		newHp += bonus + equipHpr;

		if (newHp < 1) {
			newHp = 1; // ＨＰＲ減少装備によって死亡はしない
		}
		// 水中での減少処理
		// ライフストリームで減少をなくせるか不明
		if (isUnderwater(tgpc)) {
			newHp -= 20;
		}
		// Lv50クエストの古代の空間1F2Fでの減少処理
		if (isLv50Quest(tgpc) && !inLifeStream) {
			newHp -= 10;
		}
		// 魔族の神殿での減少処理
		if (tgpc.getMapId() == 410 && !inLifeStream) {
			newHp -= 10;
		}
		if (newHp < 1) {
			if (tgpc.isGm()) {
				newHp = 1;
			} else {
				tgpc.death(null); // ＨＰが０になった場合は死亡する。
			}
		}

		if (!tgpc.isDead()) {
			tgpc.setCurrentHp(Math.min(newHp, tgpc.getMaxHp()));
		}
	}

	private 血量恢復控制() {
		// 技能回復HP增加
		_skill.put(NATURES_TOUCH, 15);
		_skill.put(COOKING_1_5_N, 3);
		_skill.put(COOKING_1_5_S, 3);
		_skill.put(COOKING_2_4_N, 2);
		_skill.put(COOKING_2_4_S, 2);
		_skill.put(COOKING_3_6_N, 2);
		_skill.put(COOKING_3_6_S, 2);

		// 地圖回復HP增加
		// 旅館
		_mapIdU.put(16384, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(16384, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(16896, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(17408, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(17920, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(18432, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(18944, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(19968, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(19456, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(20480, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(20992, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(21504, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(22016, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(22528, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(23040, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(23552, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(24064, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(24576, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(25088, Config.Hp_Reg_of_INHOTEL);
		_mapIdU.put(1784, Config.Hp_Reg_of_INHOTEL);

		// 城堡
		_mapIdU.put(15, Config.Hp_Reg_of_INHOUSE);// 肯特內城
		_mapIdU.put(29, Config.Hp_Reg_of_INHOUSE);// 風木城內城
		_mapIdU.put(52, Config.Hp_Reg_of_INHOUSE);// 奇岩內城
		_mapIdU.put(64, Config.Hp_Reg_of_INHOUSE);// 海音城堡
		// this._mapIdU.put(66, 15);// 侏儒洞穴
		_mapIdU.put(300, 15);// 亞丁內城

		// HP減少的MAP(任務MAP)
		_mapIdD.put(410, -10);// 魔族神殿
	}

	/**
	 * PC HP回復執行 判斷
	 *
	 * @param tgpc
	 * @return true:執行 false:不執行
	 */
	protected boolean check(final L1PcInstance tgpc) {
		try {
			// 人物為空
			if (tgpc == null) {
				return false;
			}

			// 人物登出
			if (tgpc.getOnlineStatus() == 0) {
				return false;
			}

			// 中斷連線
			if (tgpc.getNetConnection() == null) {
				return false;
			}

			// 死亡
			if (tgpc.isDead()) {
				return false;
			}

			// 傳送狀態
			if (tgpc.isTeleport()) {
				return false;
			}

			// 人物在降低HP地圖中
			final Integer dhp = _mapIdD.get(new Integer(tgpc.getMapId()));
			if (dhp != null) {
				return true;
			}

			// 海底
			if (isUnderwater(tgpc)) {
				return true;
			}

			// HP已滿
			if (tgpc.getCurrentHp() >= tgpc.getMaxHp()) {
				return false;
			}
			if (!tgpc.getHpRegenActive()) {
				return false;
			}

		} catch (final Exception e) {
			_log.log(Level.WARNING, e.getLocalizedMessage(), e);
			return false;
		}
		return true;
	}

	protected void checkRegenHp(final L1PcInstance tgpc) {
		try {
			tgpc.set_hpRegenType(tgpc.hpRegenType() + tgpc.getHpRegenState());
			tgpc.setRegenState(REGENSTATE_NONE);

			if (tgpc.isRegenHp()) {
				regenHp(tgpc);
			}

		} catch (final Exception e) {
			_log.log(Level.WARNING, e.getLocalizedMessage(), e);
		}
	}

}
